#pragma once

#include "Thread.hpp"
#include "log.hpp"
#include "Cond.hpp"
#include "Mutex.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <queue>

using namespace ephemerals;
using namespace LogModule;

template<class T>
class ThreadPool
{
    ThreadPool(int num = 5)
        :_num(num)
        , _isrunning(false)
    {
        for(int i = 0; i < _num; i++)
        {
            _threads.emplace_back([this](){ Task(); });
        }
    }

    void Start()
    {
        if(_isrunning) return;
        _isrunning = true;
        for(auto& t : _threads)
        {
            t.Start();
            LOG(LogLevel::INFO) << t.name() << "线程启动";
        }
    }

    ThreadPool(const ThreadPool& tp) = delete;
    ThreadPool& operator=(const ThreadPool& tp) = delete;
public:
    //懒汉方式构建对象
    static ThreadPool<T>* getInstance()
    {
        //创建单例对象需要原子性，但获取并使用单例可以不用加锁
        //双层判断提高获取单例的效率
        LOG(LogLevel::DEBUG) << "获取单例";
        if(inc == nullptr)
        {
            MutexGuard mx(_static_mutex);
            if(inc == nullptr)
            {
                LOG(LogLevel::DEBUG) << "首次使用单例，创建线程池对象";
                inc = new ThreadPool<T>();
                inc->Start();
            }
        }
        return inc;
    }

    void Stop()
    {
        if(!_isrunning) return;
        _isrunning = false;

        //唤醒全部线程
        MutexGuard mx(_mutex);
        if(_sleepnum)
            _cond.Broadcast();
    }

    void Join()
    {
        for(auto& t : _threads)
        {
            t.Join();
        }
    }

    //给线程push任务
    bool Push(const T& in)
    {
        if(_isrunning) // 只有运行状态才入队列
        {
            MutexGuard mx(_mutex);
            _taskq.push(in);
            
            //如果所有线程都在休眠，那就唤醒一个，让它做任务
            if(_threads.size() == _sleepnum)
            {
                _cond.Signal();
            }
            return true;
        }
        return false;
    }

    //由当前线程执行任务
    void Task()
    {
        char name[128] = {0};
        pthread_getname_np(pthread_self(), name, sizeof name);
        while(true)
        {
            T t;
            {
                MutexGuard mx(_mutex);
                while(_taskq.empty() && _isrunning)
                {
                    _sleepnum++;
                    _cond.Wait(_mutex);
                    _sleepnum--;
                }

                //如果线程被唤醒，且此时队列为空，且线程池停止工作，就让线程退出
                if(_taskq.empty() && !_isrunning)
                {
                    LOG(LogLevel::INFO) << name << "线程退出";
                    break;
                }

                //此时一定有任务
                t = _taskq.front();
                _taskq.pop();
            }
            //获取到任务后，在非临界区执行任务
            t();
        }
    }

private:
    int _num; // 线程的数量
    bool _isrunning; // 是否已经启动
    int _sleepnum = 0; // 因条件变量休眠的线程数
    std::vector<Thread> _threads; // 线程池
    std::queue<T> _taskq; // 任务队列
    Cond _cond;
    Mutex _mutex;

    //单例指针
    static ThreadPool<T>* inc;
    //申请单例对应的静态成员锁
    static Mutex _static_mutex;
};

template<class T>
ThreadPool<T>* ThreadPool<T>::inc = nullptr;

template<class T>
Mutex ThreadPool<T>::_static_mutex;